/*
** $身份: 嘞操作系统库.c $
** 标准操作系统库
** 见版权声明于 炉啊.h
*
* * * 本人所用声母表: a啊 b哔 c西 d迪 e鹅 f弗 g哥 
* h喝 i艾 j鸡 k颗 l嘞 m摸 n恩
* o欧 p匹 q气 r日 s丝 t嚏 
* u由 v微 w屋 x斯 y医 z只
*
* 一些英文单词缩写,我的翻译大多来自;有道词典,谷歌翻译,百度.
* 一些术语实在不好翻译,所以就原封不动.
* 
* 一些特有的表示特有库的术语是无法翻译的 *
* 否则编译器不能识别不能通过,第一版汉化就行不通.
* 
*/

#define 嘞操作系统库_西
#define 炉啊_库

#include "嘞前缀.h"


#include <errno.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "炉啊.h"

#include "嘞辅库.h"
#include "炉啊库.h"

/*
** {==================================================================
**  '串弗时间' 函数的有效转换说明符列表;
** 选项按长度分组; 长度为2的组以 '||' 开头.
** ===================================================================
*/

#if !defined(炉啊_串弗时间选项)	/* { */

/* 选项为 ANSI C 89 美国国家标准学会 C 89版 (只有1个印刻选项) */
#define 嘞_串弗时间C89		"aAbBcdHIjmMpSUwWxXyYZ%"

/* 选项为 ISO C 99 and POSIX 国际标准化组织 C 99版 与 可移植操作系统接口*/
#define 嘞_串弗时间C99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
    "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"  /* 2个印刻选项 */

/* 选项为 Windows */
#define 嘞_串弗时间WIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
    "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"  /* 2个印刻选项 */

#if defined(炉啊_用_WINDOWS)
#define 炉啊_串弗时间选项	嘞_串弗时间WIN
#elif defined(炉啊_用_C89)
#define 炉啊_串弗时间选项	嘞_串弗时间C89
#else  /* C99 规格 */
#define 炉啊_串弗时间选项	嘞_串弗时间C99
#endif

#endif					/* } */

/* }================================================================== */


/*
** {==================================================================
** 配置与时间相关的东西
** ===================================================================
*/

/*
** 类型去代表 time_t 在炉啊中
*/

#if !defined(炉啊_号时间)	/* { */

#define 嘞_时间嚏			炉啊_整数
#define 嘞_推时间(嘞,嚏)		炉啊_推整数(嘞,(炉啊_整数)(嚏))
#define 嘞_取时间(嘞,参数)	炉啊嘞_检查整数(嘞, 参数)

#else				/* }{ */

#define 嘞_时间嚏			炉啊_号码
#define 嘞_推时间(嘞,嚏)		炉啊_推号码(嘞,(炉啊_号码)(嚏))
#define 嘞_取时间(嘞,参数)	炉啊嘞_检查号码(嘞, 参数)

#endif				/* } */

#if !defined(嘞_哥摸时间)		/* { */
/*
** 默认情况下, 炉啊使用 哥摸时间/本地时间, 除非当POSIX(可移植操作系统接口)可用,
** 那里他用 哥摸时间_日/本地时间_日
*/

#if defined(炉啊_用_POSIX可移植操作系统接口)	/* { */

#define 嘞_哥摸时间(嚏,日)		哥摸时间_日(嚏,日)
#define 嘞_本地时间(嚏,日)	本地时间_日(嚏,日)

#else				/* }{ */

/* ISO C 国际标准化组织 C 定义 */
#define 嘞_哥摸时间(嚏,日)		((void)(日)->嚏摸_秒, 哥摸时间(嚏))
#define 嘞_本地时间(嚏,日)	((void)(日)->嚏摸_秒, 本地时间(嚏))

#endif				/* } */

#endif				/* } */

/* }================================================================== */

/*
** {==================================================================
** 配置为 '临时名':
** 默认情况下, 除非POSIX(可移植操作系统接口)可用,否则炉啊使用临时名, 
*  那里他用 摸颗丝临时.
** ===================================================================
*/

#if !defined(炉啊_临时名)	/* { */

#if defined(炉啊_用_POSIX可移植操作系统接口)	/* { */

#include <unistd.h>

#define 炉啊_临时名缓冲大小	32

#if !defined(炉啊_临时名模板)
#define 炉啊_临时名模板	"/临时/炉啊_XXXXXX"
#endif

#define 炉啊_临时名(哔,鹅) { \
        strcpy(哔, 炉啊_临时名模板); \
        鹅 = 摸颗丝临时(哔); \
        if (鹅 != -1) 关闭(鹅); \
        鹅 = (鹅 == -1); }

#else				/* }{ */

/* ISO C 国际标准化组织 C 定义 */
#define 炉啊_临时名缓冲大小	嘞_临时名
#define 炉啊_临时名(哔,鹅)		{ 鹅 = (临时名(哔) == NULL); }

#endif				/* } */

#endif				/* } */

/* }================================================================== */



static int 操作系统_执行 (炉啊_国 *嘞) {
  const char *命令行 = 炉啊嘞_选串(嘞, 1, NULL);
  int 洲;
  错不 = 0;
  洲 = 系统(命令行);
  if (命令行 != NULL)
    return 炉啊嘞_执行结果(嘞, 洲);
  else {
    炉啊_推布尔(嘞, 洲);  /* 如果有壳则为真 */
    return 1;
  }
}

static int 操作系统_移除 (炉啊_国 *嘞) {
  const char *文件名 = 炉啊嘞_检查串(嘞, 1);
  return 炉啊嘞_文件结果(嘞, 移除(文件名) == 0, 文件名);
}


static int 操作系统_重命名 (炉啊_国 *嘞) {
  const char *来自名字 = 炉啊嘞_检查串(嘞, 1);
  const char *到名字 = 炉啊嘞_检查串(嘞, 2);
  return 炉啊嘞_文件结果(嘞, 重命名(来自名字, 到名字) == 0, NULL);
}

static int 操作系统_临时名 (炉啊_国 *嘞) {
  char 缓冲[炉啊_临时名缓冲大小];
  int 错;
  炉啊_临时名(缓冲, 错);
  if (错)
    return 炉啊嘞_错误(嘞, "无法生成唯一的文件名");
  炉啊_推串(嘞, 缓冲);
  return 1;
}


static int 操作系统_取环境 (炉啊_国 *嘞) {
  炉啊_推串(嘞, 取环境(炉啊嘞_检查串(嘞, 1)));  /* 若 NULL 推 零 */
  return 1;
}


static int 操作系统_时钟 (炉啊_国 *嘞) {
  炉啊_推号码(嘞, ((炉啊_号码)时钟())/(炉啊_号码)时钟_每_秒);
  return 1;
}

/*
** {======================================================
** 时间/日期 操作
** { 年=%医, 月=%摸, 日=%迪, 时=%喝, 分=%大摸, 秒=%丝,
**   周=%屋+1, 昨日=%鸡, 是否夏令时=? }
** =======================================================
*/

/*
** 关于溢出检查: 当时间用 炉啊_整数 表示时，不会发生溢出,
*  因为 炉啊_整数 足够大,代表所有整型字段或代表一个时间不够大,导致一个字段溢出.
*   然而, 如果时间表示为 双浮 和 炉啊_整数 为 整型, 
** 那么时间 0x1.e1853b0d184f6p+55 将导致1900相加计算年份时溢出.
*/

static void 设置字段 (炉啊_国 *嘞, const char *键, int 值, int 德尔塔) {
  #if (defined(炉啊_号时间) && 炉啊_最大整数 <= 整型_最大)
    if (值 > 炉啊_最大整数 - 德尔塔)
      炉啊嘞_错误(嘞, "字段 '%s' 是出界", 键);
  #endif
  炉啊_推整数(嘞, (炉啊_整数)值 + 德尔塔);
  炉啊_设置字段(嘞, -2, 键);
}


static void 设置布尔字段 (炉啊_国 *嘞, const char *键, int 值) {
  if (值 < 0)  /* 未定义的? */
    return;  /* 不设置字段 */
  炉啊_推布尔(嘞, 值);
  炉啊_设置字段(嘞, -2, 键);
}

/*
** 设置所有字段来自于结构"标签方法"于表内在栈顶,
*/
static void 设置所有字段 (炉啊_国 *嘞, struct 标签方法 *丝标签方法) {
  设置字段(嘞, "年", 丝标签方法->标签方法_年, 1900);
  设置字段(嘞, "月", 丝标签方法->标签方法_月, 1);
  设置字段(嘞, "日", 丝标签方法->标签方法_摸日, 0);
  设置字段(嘞, "时", 丝标签方法->标签方法_时, 0);
  设置字段(嘞, "分", 丝标签方法->标签方法_分, 0);
  设置字段(嘞, "秒", 丝标签方法->标签方法_秒, 0);
  设置字段(嘞, "昨日", 丝标签方法->标签方法_昨日, 1);
  设置字段(嘞, "周", 丝标签方法->标签方法_周, 1);
  设置布尔字段(嘞, "是否夏令时", 丝标签方法->标签方法_是否夏令时);
}

static int 取布尔字段 (炉啊_国 *嘞, const char *键) {
  int 结;
  结 = (炉啊_取字段(嘞, -1, 键) == 炉啊_嚏零) ? -1 : 炉啊_到布尔(嘞, -1);
  炉啊_弹(嘞, 1);
  return 结;
}

static int 取字段 (炉啊_国 *嘞, const char *键, int 迪, int 德尔塔) {
  int 是否号码;
  int 嚏 = 炉啊_取字段(嘞, -1, 键);  /* 取字段和它的类型 */
  炉啊_整数 结 = 炉啊_到整数斯(嘞, -1, &是否号码);
  if (!是否号码) {  /* 字段不是整数? */
    if (嚏 != 炉啊_嚏零)  /* 其他值? */
      return 炉啊嘞_错误(嘞, "字段 '%s' 不是整数", 键);
    else if (迪 < 0)  /* 缺席字段;无默认? */
      return 炉啊嘞_错误(嘞, "字段 '%s' 遗失日期表", 键);
    结 = 迪;
  }
  else {
    /* 当 炉啊_整数 有32位时,无符号避免溢出 */
    if (!(结 >= 0 ? (炉啊_无符号)结 <= (炉啊_无符号)整型_最大 + 德尔塔
                   : (炉啊_整数)整型_最小 + 德尔塔 <= 结))
      return 炉啊嘞_错误(嘞, "字段 '%s' 不受约束的", 键);
    结 -= 德尔塔;
  }
  炉啊_弹(嘞, 1);
  return (int)结;
}

static const char *检查选项 (炉啊_国 *嘞, const char *转换,
                                ptrdiff_t 转换长度, char *缓冲) {
  const char *选项 = 炉啊_串弗时间选项;
  int 操作长度 = 1;  /* 已检查选项的长度 */
  for (; *选项 != '\0' && 操作长度 <= 转换长度; 选项 += 操作长度) {
    if (*选项 == '|')  /* 下一个块? */
      操作长度++;  /* 将检查选项和下一个长度吗 (+1) */
    else if (memcmp(转换, 选项, 操作长度) == 0) {  /* 匹配? */
      memcpy(缓冲, 转换, 操作长度);  /* 将有效选项复制到缓冲区 */
      缓冲[操作长度] = '\0';
      return 转换 + 操作长度;  /* 返回下一个项目 */
    }
  }
  炉啊嘞_实参错误(嘞, 1,
    炉啊_推弗串(嘞, "无效转换说明符 '%%%s'", 转换));
  return 转换;  /* 避免警告 */
}

static time_t 嘞_检查时间 (炉啊_国 *嘞, int 实参) {
  嘞_时间嚏 嚏 = 嘞_取时间(嘞, 实参);
  炉啊嘞_实参检查(嘞, (time_t)嚏 == 嚏, 实参, "时间出界");
  return (time_t)嚏;
}

/* 个别 '串弗时间' 项的最大大小 */
#define 大小时间编排	250

static int 操作系统_日期 (炉啊_国 *嘞) {
  size_t 丝长;
  const char *丝 = 炉啊嘞_选项嘞串(嘞, 1, "%c", &丝长);
  time_t 嚏 = 炉啊嘞_选项(嘞, 嘞_检查时间, 2, 时间(NULL));
  const char *丝鹅 = 丝 + 丝长;  /* '丝' 终 */
  struct 标签方法 嚏摸日, *丝嚏摸;
  if (*丝 == '!') {  /* UTC协调世界时? */
    丝嚏摸 = 嘞_哥摸时间(&嚏, &嚏摸日);
    丝++;  /* 跳过 '!' */
  }
  else
    丝嚏摸 = 嘞_本地时间(&嚏, &嚏摸日);
  if (丝嚏摸 == NULL)  /* 无效的日期? */
    return 炉啊嘞_错误(嘞,
                 "在此安装中无法表示日期结果");
  if (strcmp(丝, "*嚏") == 0) {
    炉啊_创建表(嘞, 0, 9);  /* 9 = 字段号码 */
    设置所有字段(嘞, 丝嚏摸);
  }
  else {
    char 西西[4];  /* 用于个别转换说明符的缓冲区 */
    炉啊嘞_缓冲 哔;
    西西[0] = '%';
    炉啊嘞_缓冲初始化(嘞, &哔);
    while (丝 < 丝鹅) {
      if (*丝 != '%')  /* 不是转换说明符? */
        炉啊嘞_加印刻(&哔, *丝++);
      else {
        size_t 结果长;
        char *缓冲 = 炉啊嘞_预缓冲大小(&哔, 大小时间编排);
        丝++;  /* 跳过 '%' */
        丝 = 检查选项(嘞, 丝, 丝鹅 - 丝, 西西 + 1);  /* 复制说明符到'西西' */
        结果长 = 串弗时间(缓冲, 大小时间编排, 西西, 丝嚏摸);
        炉啊嘞_加大小(&哔, 结果长);
      }
    }
    炉啊嘞_推结果(&哔);
  }
  return 1;
}

static int 操作系统_时间 (炉啊_国 *嘞) {
  time_t 嚏;
  if (炉啊_是否空缺或零(嘞, 1))  /* 无实参调用? */
    嚏 = 时间(NULL);  /* 取当前时间 */
  else {
    struct 标签方法 嚏丝;
    炉啊嘞_检查类型(嘞, 1, 炉啊_嚏表);
    炉啊_设置顶部(嘞, 1);  /* 确保表在顶部 */
    嚏丝.标签方法_年 = 取字段(嘞, "年", -1, 1900);
    嚏丝.标签方法_月 = 取字段(嘞, "月", -1, 1);
    嚏丝.标签方法_摸日 = 取字段(嘞, "日", -1, 0);
    嚏丝.标签方法_时 = 取字段(嘞, "时", 12, 0);
    嚏丝.标签方法_分 = 取字段(嘞, "分", 0, 0);
    嚏丝.标签方法_秒 = 取字段(嘞, "秒", 0, 0);
    嚏丝.标签方法_是否夏令时 = 取布尔字段(嘞, "是否夏令时");
    嚏 = 摸颗时间(&嚏丝);
    设置所有字段(嘞, &嚏丝);  /* 更新归一化值的字段 */
  }
  if (嚏 != (time_t)(嘞_时间嚏)嚏 || 嚏 == (time_t)(-1))
    return 炉啊嘞_错误(嘞,
                  "在此安装中不能表示时间结果");
  嘞_推时间(嘞, 嚏);
  return 1;
}

static int 操作系统_不同时间 (炉啊_国 *嘞) {
  time_t 嚏1 = 嘞_检查时间(嘞, 1);
  time_t 嚏2 = 嘞_检查时间(嘞, 2);
  炉啊_推号码(嘞, (炉啊_号码)不同时间(嚏1, 嚏2));
  return 1;
}

/* }====================================================== */

static int 操作系统_设置本地 (炉啊_国 *嘞) {
  static const int 猫[] = {嘞西_所有, 嘞西_核对, 嘞西_西类型, 嘞西_货币,
                      嘞西_数号, 嘞西_时间};
  static const char *const 猫名字[] = {"所有", "核对", "西类型", "货币",
     "数号", "时间", NULL};
  const char *小嘞 = 炉啊嘞_选择串(嘞, 1, NULL);
  int 操作 = 炉啊嘞_检查选择(嘞, 2, "所有", 猫名字);
  炉啊_推串(嘞, 设置本地(猫[操作], 小嘞));
  return 1;
}

static int 操作系统_退出 (炉啊_国 *嘞) {
  int 状态;
  if (炉啊_是否布尔(嘞, 1))
    状态 = (炉啊_到布尔(嘞, 1) ? 退出_成功 : 退出_失败);
  else
    状态 = (int)炉啊嘞_选择整数(嘞, 1, 退出_成功);
  if (炉啊_到布尔(嘞, 2))
    炉啊_关闭(嘞);
  if (嘞) 退出(状态);  /* '若' 以避免无法到达的警告 '返回' */
  return 0;
}

static const 炉啊嘞_寄存 系统库[] = {
  {"时钟",     操作系统_时钟},
  {"日期",      操作系统_日期},
  {"不同时间",  操作系统_不同时间},
  {"执行",   操作系统_执行},
  {"退出",      操作系统_退出},
  {"取环境",    操作系统_取环境},
  {"移除",    操作系统_移除},
  {"重命名",    操作系统_重命名},
  {"设置本地", 操作系统_设置本地},
  {"时间",      操作系统_时间},
  {"临时名",   操作系统_临时名},
  {NULL, NULL}
};

/* }====================================================== */



炉啊模_应用程序接口 int 炉啊打开_操作系统 (炉啊_国 *嘞) {
  炉啊嘞_新库(嘞, 系统库);
  return 1;
}

